package cluster

import (
	"context"
	"errors"
	"go-redis/cons"
	"go-redis/interface/resp"
	"go-redis/lib/utils"
	"go-redis/resp/client"
	"go-redis/resp/reply"
	"strconv"
)

// 获取peer的连接客户端
func (cluster *ClusterDatabase) getPeerClient(peer string) (*client.Client, error) {
	if len(cluster.peerConnection) == 0 {
		return nil, errors.New("peer connections not exists")
	}
	pool, ok := cluster.peerConnection[peer]
	if !ok {
		return nil, errors.New("connection factory not found")
	}
	raw, err := pool.BorrowObject(context.Background())
	if err != nil {
		return nil, err
	}
	c, ok := raw.(*client.Client)
	if !ok {
		return nil, errors.New("connection factory make wrong type")
	}
	return c, nil
}

// 归还peer的连接客户端
func (cluster *ClusterDatabase) returnPeerClient(peer string, client *client.Client) error {
	if len(cluster.peerConnection) == 0 {
		return errors.New("peer connections not exists")
	}
	pool, ok := cluster.peerConnection[peer]
	if !ok {
		return errors.New("connection factory not found")
	}

	return pool.ReturnObject(context.Background(), client)
}

// 请求转发
func (cluster *ClusterDatabase) dispatcher(peer string, c resp.Connection, args [][]byte) resp.Reply {
	// 转发到当前的数据库即可
	if peer == cluster.self {
		return cluster.db.Exec(c, args)
	}
	peerClient, err := cluster.getPeerClient(peer)
	if err != nil {
		return reply.MakeErrReply(err.Error())
	}
	defer func() {
		_ = cluster.returnPeerClient(peer, peerClient)
	}()
	// 先发送select db的指令
	peerClient.Send(utils.ToCmdLine(cons.CmdSelect, strconv.Itoa(c.GetDBIndex())))
	// 发送真正的执行指令
	return peerClient.Send(args)
}

// 广播指令
func (cluster *ClusterDatabase) broadcast(c resp.Connection, args [][]byte) map[string]resp.Reply {
	result := make(map[string]resp.Reply)
	for _, node := range cluster.nodes {
		resply := cluster.dispatcher(node, c, args)
		result[node] = resply
	}
	return result
}
